
/* <<< COPYRIGHT START >>>
 * Copyright 2006-Present OxygenSoftwareLibrary.com
 * Licensed under the GNU Lesser General Public License.
 * http://www.gnu.org/licenses/lgpl.html
 * 
 * @author: Ugorji Dick-Nwoke
 * <<< COPYRIGHT END >>>
 */


package oxygen.extensions.tomcat;

import java.security.Principal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

import javax.naming.Context;
import javax.sql.DataSource;

import org.apache.catalina.ServerFactory;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.realm.RealmBase;

/*
 * *************************************
TABLE jforum_users
  user_id mediumint(8) NOT NULL auto_increment,
  username varchar(50) NOT NULL default '',
  user_password varchar(32) NOT NULL default '',
  security_hash varchar(32),
TABLE jforum_user_groups
  group_id INT NOT NULL,
  user_id INT NOT NULL,
TABLE jforum_groups
  group_id mediumint(8) NOT NULL auto_increment,
  group_name varchar(40) NOT NULL default '',
 * *************************************
*/
public class JForumBasedRealm extends RealmBase {
  
  private static String SELECT_PASSWORD_QUERY = 
    "SELECT user_password from jforum_users where username = ?";
  private static String SELECT_GROUPS_QUERY = 
    "SELECT G.group_name from jforum_groups G, jforum_user_groups UG, jforum_users U " +
    " WHERE UG.group_id = G.group_id " + 
    " AND UG.user_id = U.user_id " + 
    " AND U.username = ?";
  
  private String datasourceName = null;
  
  public void setDatasourceName(String s) {
    datasourceName = s;
  }
  
  protected String getName() {
    return "JForumBasedRealm";
  }
  
  protected String getPassword(String username) {
    String pw = null;
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
      conn = getConnection();
      pstmt = conn.prepareStatement(SELECT_PASSWORD_QUERY);
      pstmt.setString(1, username);
      rs = pstmt.executeQuery();
      if(rs.next()) {
        pw = rs.getString(1);
      }
    } catch(Exception exc) {
      throw new RuntimeException(exc);
    } finally {
      close(rs, pstmt, conn);
    }
    return pw;
  }
  
  protected Principal getPrincipal(String username) {
    Principal principal = null;
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
      String pw = getPassword(username);
      conn = getConnection();
      //get the roles (as strings) into an ArrayList
      ArrayList roles = new ArrayList();
      pstmt = conn.prepareStatement(SELECT_GROUPS_QUERY);
      pstmt.setString(1, username);
      rs = pstmt.executeQuery();
      while(rs.next()) {
        roles.add(rs.getString(1));
      }
      principal = new GenericPrincipal(this, username, getPassword(username), roles);
    } catch(Exception exc) {
      throw new RuntimeException(exc);
    } finally {
      close(rs, pstmt, conn);
    }
    return principal;
  }

  private void close(ResultSet rs, PreparedStatement pstmt, Connection conn) {
    try { if(rs != null) {rs.close(); } } catch(Exception exc) { };
    try { if(pstmt != null) {pstmt.close(); } } catch(Exception exc) { };
    try { if(conn != null) {conn.close(); } } catch(Exception exc) { };
  }

  private Connection getConnection() throws Exception {
    StandardServer server = (StandardServer) ServerFactory.getServer();
    Context context = server.getGlobalNamingContext();
    DataSource dataSource = (DataSource)context.lookup(datasourceName);
    Connection conn = dataSource.getConnection();
    return conn;
  }
  
  
  /*
   * ***************************************************
  private static String SELECT_USERID_QUERY = 
    "SELECT user_id from jforum_users where username = ? AND user_password = ?";
  private static String SELECT_GROUPS_BY_USERID_QUERY = 
    "SELECT G.group_name from jforum_groups G, jforum_user_groups UG, jforum_users U " +
    " WHERE UG.group_id = G.group_id " + 
    " AND UG.user_id = U.user_id " + 
    " AND U.user_id = ?";
  * ***************************************************
  */

  /*
   * ***************************************************
  public Principal authenticate(String username, String credentials) {
    if (username == null || username.length() == 0) {
      throw new IllegalArgumentException("Username cannot be null or zero length");
    }
    //*** if we can't authenticate, return null
    GenericPrincipal principal = null;
    int user_id = -99999;
    StandardServer server = (StandardServer) ServerFactory.getServer();
    Context context = server.getGlobalNamingContext();
    DataSource dataSource = (DataSource)context.lookup(datasourceName);
    Connection conn = dataSource.getConnection();

    //get the password, and validate it
    PreparedStatement pstmt = conn.prepareStatement(SELECT_USERID_QUERY);
    pstmt.setString(1, username);
    pstmt.setString(2, crypt(credentials));
    ResultSet rs = pstmt.executeQuery();
    if(rs.next()) {
      user_id = rs.getInt(1);
    }
    pstmt.close();
    if(user_id == -99999) {
      return null;
    } 
    
    //get the roles (as strings) into an ArrayList
    ArrayList roles = new ArrayList();
    pstmt = conn.prepareStatement(SELECT_GROUPS_BY_USERID_QUERY);
    pstmt.setInt(1, user_id);
    rs = pstmt.executeQuery();
    while(rs.next()) {
      roles.add(rs.getString(1));
    }
    principal = new GenericPrincipal(this, username, credentials, roles);
    return principal;
  }
  
  private static String crypt(String str) throws Exception {		
    StringBuffer hexString = new StringBuffer();		
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(str.getBytes());
    byte[] hash = md.digest();
			
    for (int i = 0; i < hash.length; i++) {
      if ((0xff & hash[i]) < 0x10) {
        hexString.append("0").append(Integer.toHexString((0xFF & hash[i])));
      }				
      else {
        hexString.append(Integer.toHexString(0xFF & hash[i]));
      }				
    }
    return hexString.toString();
  }
  * ***************************************************
  */

}


